//SPDX-FileCopyrightText: Copyright 2022-2024 深圳市同心圆网络有限公司
//SPDX-License-Identifier: GPL-3.0-only

package org_dao

import (
	"context"

	"atomgit.com/openlinksaas-org/api-server/dao/db_ns"
	"atomgit.com/openlinksaas-org/proto-gen-go.git/org_forum_api"
	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/mongo"
	"go.mongodb.org/mongo-driver/mongo/options"
)

type ThreadContentInfoDbItem struct {
	ContentId  string `bson:"_id"`
	OrgId      string `bson:"orgId"`
	ForumId    string `bson:"forumId"`
	ThreadId   string `bson:"threadId"`
	Content    string `bson:"content"`
	UserId     string `bson:"userId"`
	CreateTime int64  `bson:"createTime"`
	UpdateTime int64  `bson:"updateTime"`
}

func (item *ThreadContentInfoDbItem) ToThreadContentInfo() *org_forum_api.ThreadContentInfo {
	return &org_forum_api.ThreadContentInfo{
		ContentId:  item.ContentId,
		ThreadId:   item.ThreadId,
		Content:    item.Content,
		UserId:     item.UserId,
		CreateTime: item.CreateTime,
		UpdateTime: item.UpdateTime,
	}
}

func (item *ThreadContentInfoDbItem) ToUserContentInfo() *org_forum_api.UserContentInfo {
	return &org_forum_api.UserContentInfo{
		ContentId:  item.ContentId,
		ForumId:    item.ForumId,
		ThreadId:   item.ThreadId,
		Content:    item.Content,
		UserId:     item.UserId,
		CreateTime: item.CreateTime,
		UpdateTime: item.UpdateTime,
	}
}

type _ThreadContentDao struct {
	mc *mongo.Collection
}

func newThreadContentDao(db *mongo.Database) (*_ThreadContentDao, error) {
	mc := db.Collection(db_ns.DB_NS_ORG + "thread_content")
	_, err := mc.Indexes().CreateMany(context.Background(), []mongo.IndexModel{
		{
			Keys: bson.D{{"orgId", 1}, {"forumId", 1}, {"threadId", 1}, {"createTime", 1}},
		},
		{
			Keys: bson.D{{"orgId", 1}, {"userId", 1}, {"createTime", 1}},
		},
	})
	if err != nil {
		return nil, err
	}
	return &_ThreadContentDao{mc: mc}, nil
}

func (db *_ThreadContentDao) Insert(ctx context.Context, dbItem *ThreadContentInfoDbItem) error {
	_, err := db.mc.InsertOne(ctx, dbItem)
	return err
}

func (db *_ThreadContentDao) Exist(ctx context.Context, orgId, forumId, threadId, contentId string) (bool, error) {
	count, err := db.mc.CountDocuments(ctx, bson.M{"orgId": orgId, "forumId": forumId, "threadId": threadId, "_id": contentId})
	return count > 0, err
}

func (db *_ThreadContentDao) SimpleGet(ctx context.Context, orgId, contentId string) (*ThreadContentInfoDbItem, error) {
	retItem := &ThreadContentInfoDbItem{}
	err := db.mc.FindOne(ctx, bson.M{"orgId": orgId, "_id": contentId}).Decode(retItem)
	return retItem, err
}

func (db *_ThreadContentDao) Get(ctx context.Context, orgId, forumId, threadId, contentId string) (*ThreadContentInfoDbItem, error) {
	retItem := &ThreadContentInfoDbItem{}
	err := db.mc.FindOne(ctx, bson.M{"orgId": orgId, "forumId": forumId, "threadId": threadId, "_id": contentId}).Decode(retItem)
	return retItem, err
}

func (db *_ThreadContentDao) Remove(ctx context.Context, orgId, forumId, threadId, contentId string) error {
	_, err := db.mc.DeleteOne(ctx, bson.M{"orgId": orgId, "forumId": forumId, "threadId": threadId, "_id": contentId})
	return err
}

func (db *_ThreadContentDao) RemoveByThread(ctx context.Context, orgId, forumId, threadId string) error {
	_, err := db.mc.DeleteMany(ctx, bson.M{"orgId": orgId, "forumId": forumId, "threadId": threadId})
	return err
}

func (db *_ThreadContentDao) RemoveByForum(ctx context.Context, orgId, forumId string) error {
	_, err := db.mc.DeleteMany(ctx, bson.M{"orgId": orgId, "forumId": forumId})
	return err
}

func (db *_ThreadContentDao) RemoveByOrg(ctx context.Context, orgId string) error {
	_, err := db.mc.DeleteMany(ctx, bson.M{"orgId": orgId})
	return err
}

func (db *_ThreadContentDao) CountByThread(ctx context.Context, orgId, forumId, threadId string) (uint32, error) {
	count, err := db.mc.CountDocuments(ctx, bson.M{"orgId": orgId, "forumId": forumId, "threadId": threadId})
	return uint32(count), err
}

func (db *_ThreadContentDao) ListByThread(ctx context.Context, orgId, forumId, threadId string, offset, limit int64) ([]*ThreadContentInfoDbItem, error) {
	cursor, err := db.mc.Find(ctx, bson.M{"orgId": orgId, "forumId": forumId, "threadId": threadId},
		options.Find().SetSkip(offset).SetLimit(limit).SetSort(bson.D{{"createTime", 1}}))
	if err != nil {
		return nil, err
	}
	retList := []*ThreadContentInfoDbItem{}
	err = cursor.All(ctx, &retList)
	return retList, err
}

func (db *_ThreadContentDao) CountByUser(ctx context.Context, orgId, userId string) (uint32, error) {
	count, err := db.mc.CountDocuments(ctx, bson.M{"orgId": orgId, "userId": userId})
	return uint32(count), err
}

func (db *_ThreadContentDao) ListByUser(ctx context.Context, orgId, userId string, offset, limit int64) ([]*ThreadContentInfoDbItem, error) {
	cursor, err := db.mc.Find(ctx, bson.M{"orgId": orgId, "userId": userId},
		options.Find().SetSkip(offset).SetLimit(limit).SetSort(bson.D{{"createTime", -1}}))
	if err != nil {
		return nil, err
	}
	retList := []*ThreadContentInfoDbItem{}
	err = cursor.All(ctx, &retList)
	return retList, err
}

func (db *_ThreadContentDao) ListById(ctx context.Context, orgId string, contentIdList []string) ([]*ThreadContentInfoDbItem, error) {
	if len(contentIdList) == 0 {
		return []*ThreadContentInfoDbItem{}, nil
	}
	cursor, err := db.mc.Find(ctx, bson.M{"orgId": orgId, "_id": bson.M{"$in": contentIdList}})
	if err != nil {
		return nil, err
	}
	retList := []*ThreadContentInfoDbItem{}
	err = cursor.All(ctx, &retList)
	return retList, err
}

func (db *_ThreadContentDao) Update(ctx context.Context, orgId, forumId, threadId, contentId, content string, updateTime int64) error {
	_, err := db.mc.UpdateOne(ctx, bson.M{"orgId": orgId, "forumId": forumId, "threadId": threadId, "_id": contentId},
		bson.M{"$set": bson.M{
			"content":    content,
			"updateTime": updateTime,
		}})
	return err
}
